package com.dap.exception;

import java.io.IOException;
import java.io.InputStream;
import java.util.*;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.helpers.MessageFormatter;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;

import com.alibaba.fastjson.JSON;
import com.dap.core.config.ConfigurationListener;

public class ErrorCodeContainer implements ConfigurationListener, InitializingBean {
    private final static Logger LOGGER = LoggerFactory.getLogger(ErrorCodeContainer.class);

    private final static String DEFAULT_LANGUAGE = "zh_CN";

    private final static String DEFAULT_PLATFORM_ERROR_CODE_CONFIG = "config/platform_errorCode_zh_CN.config";


    private final static Map<String, Map<String, String>> LANGUAGE_ERROR_MAPPINGS = new HashMap<>();

    private static boolean inited = false;

    private List<String> configKeys = new ArrayList<>();
    private Resource[] locations = new Resource[0];


    @Override
    public void resourceChanged(String configKey, Resource configResource) {
        LOGGER.info("resourceChanged, configKey={}  configFileName={}", configKey, configResource.getFilename());
        loadErrorCodeConfig(configResource);
    }


    @Override
    public void configChanged(String configKey, Properties properties) {
        LOGGER.info("configKey:{}  {}", configKey, properties);
    }


    @Override
    public List<String> getConfigKeys() {
        return this.configKeys;
    }


    @Override
    public void afterPropertiesSet() throws Exception {
        loadErrorCodeConfig(new ClassPathResource(DEFAULT_PLATFORM_ERROR_CODE_CONFIG));
        for (Resource resource : locations) {
            loadErrorCodeConfig(resource);
        }
        LOGGER.debug("error properties config:{}", JSON.toJSONString(LANGUAGE_ERROR_MAPPINGS));
        inited = true;
    }


    // 不使用spring加载
    private static synchronized void loadDefaultConfig() {
        if (!inited) {
            try {
                loadErrorCodeConfig(new ClassPathResource(DEFAULT_PLATFORM_ERROR_CODE_CONFIG));
            } catch (Exception e) {
                LOGGER.warn("", e);
            }
            LOGGER.debug("error properties config:{}", JSON.toJSONString(LANGUAGE_ERROR_MAPPINGS));
            inited = true;
        }
    }


    public void setConfigKeys(List<String> configKeys) {
        this.configKeys = configKeys;
    }


    public Resource[] getLocations() {
        return locations;
    }


    public void setLocations(Resource[] locations) {
        this.locations = locations;
    }


    private static String getLanguageFromFileName(String fileName) {
        final String languagePrefix = "errorCode_", languageSuffix = ".config";
        int languagePrefixIdx = fileName.indexOf(languagePrefix);
        int languageSuffixIdx = fileName.lastIndexOf(languageSuffix);

        if (languagePrefixIdx >= 0 && languageSuffixIdx >= 0 && languagePrefixIdx < languageSuffixIdx) {
            return fileName.substring(languagePrefixIdx + languagePrefix.length(), languageSuffixIdx);
        } else {
            return DEFAULT_LANGUAGE;
        }
    }

    private static void loadErrorCodeConfig(Resource res) {
        String fileName = res.getFilename();
        InputStream in = null;
        try {
            in = res.getInputStream();
            Properties newProperties = new Properties();
            newProperties.load(in);
            Map<String, String> newMap = propertiesToMap(newProperties);

            String language = getLanguageFromFileName(fileName);
            Map<String, String> oldMap = LANGUAGE_ERROR_MAPPINGS.get(language);
            // 不存在,新增
            if (null == oldMap) {
                LANGUAGE_ERROR_MAPPINGS.put(language, newMap);
            }
            // 存在, 合并
            else {
                for (Map.Entry<String, String> entry : newMap.entrySet()) {
                    oldMap.put(entry.getKey(), entry.getValue());
                }
            }

            LOGGER.info("load error properties file  > {} success !", fileName);
        } catch (IOException e) {
            LOGGER.error("", e);
        } catch (Exception e) {
            LOGGER.error("", e);
        } finally {
            try {
                if (in != null)
                    in.close();
            } catch (IOException e) {
            }
        }
    }
    private static Map<String, String> propertiesToMap(Properties properties) {
        Map<String, String> map = new HashMap<>(2048);
        for (String key : properties.stringPropertyNames()) {
            map.put(key, properties.getProperty(key));
        }
        return map;
    }


    /**
     * 根据错误码获取对应的错误信息, 并将参数替换通配符{}
     *
     * @param errorCode 错误码
     * @param pattern   匹配参数
     * @return
     */
    public static String getErrorMessage(String errorCode, String... pattern) {
        if (!inited) {
            loadDefaultConfig();
        }

        Map<String, String> errorMap = LANGUAGE_ERROR_MAPPINGS.get(DEFAULT_LANGUAGE);
        String message = errorMap.get(errorCode);

        if (null == message || message.trim().isEmpty()) {
            LOGGER.warn("未找到错误码[{}]的定义!", errorCode);
            if (pattern != null) {
                if (pattern.length == 1) {
                    return pattern[0];
                } else if (pattern.length > 1) {
                    return Arrays.toString(pattern);
                }
            }
            return "";
        } else {
            return MessageFormatter.arrayFormat(message, pattern).getMessage();
        }
    }

}